// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: support agent between domain
// feature: agent endpoints created by dserver discovery result
// feature: provide query interfaces
// feature: develop dispatcher
// feature: discovery support client and server
// ------------------------------------------------------------------

#ifndef _EDDS_RTPS_DISCOVERY_ENDPOINT_INFO_H_
#define _EDDS_RTPS_DISCOVERY_ENDPOINT_INFO_H_

#include <discovery/database/DiscoverySharedInfo.hpp>

#include <ertps/utils/fixed_size_string.hpp>

#include <history/CacheChange.h>
#include <edds/rtps/common/GuidPrefix_t.hpp>

#include <nlohmann/json.hpp>

#include <xmlparser/qos/XMLReaderQos.hpp>
#include <xmlparser/qos/XMLWriterQos.hpp>
namespace evbs {
namespace ertps {
namespace rtps {
namespace ddb {

class EndpointQos {
 public:
    EndpointQos(const vbsutil::xmlparser::ReaderQos& reader_qos) {
        m_durability = reader_qos.m_durability;
        m_deadline = reader_qos.m_deadline;
        m_liveliness = reader_qos.m_liveliness;
        m_reliability = reader_qos.m_reliability;
        m_ownership = reader_qos.m_ownership;
        m_disablePositiveACKs = reader_qos.m_disablePositiveACKs;
        m_e2eProtecion = reader_qos.m_e2eProtecion;
        m_isMultiSend = reader_qos.m_isMultiSend;
        m_history = reader_qos.m_history;
        m_resourceLimits = reader_qos.m_resourceLimits;
        m_agent_flag = reader_qos.m_agent_flag;
    }
    EndpointQos(const vbsutil::xmlparser::WriterQos& writer_qos) {
        m_durability = writer_qos.m_durability;
        m_deadline = writer_qos.m_deadline;
        m_liveliness = writer_qos.m_liveliness;
        m_reliability = writer_qos.m_reliability;
        m_ownership = writer_qos.m_ownership;
        m_disablePositiveACKs = writer_qos.m_disablePositiveACKs;
        m_e2eProtecion = writer_qos.m_e2eProtecion;
        m_isMultiSend = writer_qos.m_isMultiSend;
        m_history = writer_qos.m_history;
        m_resourceLimits = writer_qos.m_resourceLimits;
        m_agent_flag = writer_qos.m_agent_flag;
    }
    EndpointQos(const EndpointQos& qos) {
        m_durability = qos.m_durability;
        m_deadline = qos.m_deadline;
        m_liveliness = qos.m_liveliness;
        m_reliability = qos.m_reliability;
        m_ownership = qos.m_ownership;
        m_disablePositiveACKs = qos.m_disablePositiveACKs;
        m_e2eProtecion = qos.m_e2eProtecion;
        m_isMultiSend = qos.m_isMultiSend;
        m_history = qos.m_history;
        m_resourceLimits = qos.m_resourceLimits;
        m_agent_flag = qos.m_agent_flag;
    }
    EndpointQos() {}
    ~EndpointQos() {}
    EndpointQos& operator=(const EndpointQos& qos) {
        m_durability.kind = qos.m_durability.kind;
        m_deadline.period = qos.m_deadline.period;
        m_liveliness.kind = qos.m_liveliness.kind;
        m_liveliness.lease_duration = qos.m_liveliness.lease_duration;
        m_liveliness.announcement_period = qos.m_liveliness.announcement_period;
        m_reliability.kind = qos.m_reliability.kind;
        m_ownership.kind = qos.m_ownership.kind;
        m_disablePositiveACKs.enabled = qos.m_disablePositiveACKs.enabled;
        m_disablePositiveACKs.duration = qos.m_disablePositiveACKs.duration;
        m_e2eProtecion = qos.m_e2eProtecion;
        m_isMultiSend = qos.m_isMultiSend;
        m_history = qos.m_history;
        m_resourceLimits = qos.m_resourceLimits;
        m_agent_flag = qos.m_agent_flag;
        return *this;
    }
    EndpointQos& operator=(EndpointQos&&) noexcept = default;

    //! Durability Qos, implemented in the library.
    vbsutil::xmlparser::DurabilityQosPolicy m_durability;

    //! Deadline Qos, implemented in the library.
    vbsutil::xmlparser::DeadlineQosPolicy m_deadline;

    //! Liveliness Qos, implemented in the library.
    vbsutil::xmlparser::LivelinessQosPolicy m_liveliness;

    //! ReliabilityQos, implemented in the library.
    vbsutil::xmlparser::ReliabilityQosPolicy m_reliability;

    //! Ownership Qos, implemented in the library.
    vbsutil::xmlparser::OwnershipQosPolicy m_ownership;

    //! Disable positive ACKs QoS
    vbsutil::xmlparser::DisablePositiveACKsQosPolicy m_disablePositiveACKs;

    //! E2E Protection QoS implemented in the library.
    vbsutil::xmlparser::E2EProtectionQosPolicy m_e2eProtecion;

    bool m_isMultiSend = false;

    uint8_t m_agent_flag = 0;

    vbsutil::xmlparser::HistoryQosPolicy m_history;

    vbsutil::xmlparser::ResourceLimitsQosPolicy m_resourceLimits;
};
/**
 * Class to join the main info required from a reader or writer in the Discovery Data Base
 *@ingroup DISCOVERY_MODULE
 */
class DiscoveryEndpointInfo : public DiscoverySharedInfo {
 public:
    DiscoveryEndpointInfo() : DiscoverySharedInfo(), is_virtual_(false), is_rpc_(false) {}

    DiscoveryEndpointInfo(CacheChange_t* change, std::string topic, bool is_virtual, bool is_rpc,
                          const GuidPrefix_t& known_participant, const EndpointQos& qos, const std::string& type_name,
                          bool take_locator, uint32_t queue_id = 0)
        : DiscoverySharedInfo(change, known_participant),
          topic_(std::move(topic)),
          type_name_(type_name),
          is_virtual_(is_virtual),
          is_rpc_(is_rpc),
          qos_(qos),
          take_locator_(take_locator),
          dsf_queue_id(queue_id) {}

    virtual ~DiscoveryEndpointInfo() = default;

    const std::string topic() const;

    const std::string type_name() const { return type_name_; }

    void is_virtual(bool is_virtual);

    bool is_virtual() const;

    void is_rpc(bool is_rpc);

    bool is_rpc() const;

    void to_json(nlohmann::json& j) const;
    void set_qos(EndpointQos& qos);

    EndpointQos get_qos() const;

    bool take_locator() const;
    void take_locator(bool take_locator);

    uint32_t get_queue_id() const;
    void set_queue_id(uint32_t queue_id);

    bool is_authenticated_writers(GuidPrefix_t writer_guid) const;
    void insert_authenticated_writers(GuidPrefix_t writer_guid);
    void remove_authenticated_writers(GuidPrefix_t writer_guid);

    bool valid_matching(DiscoveryEndpointInfo& winfo, const GUID_t& writer_guid, DiscoveryEndpointInfo& rinfo,
                        const GUID_t& reader_guid);

 private:
    std::string topic_;
    std::string type_name_;
    bool is_virtual_;
    bool is_rpc_;
    EndpointQos qos_;
    bool take_locator_;
    uint32_t dsf_queue_id;
    // Only used by the dsf reader to query whether the remote writer is securely authenticated.
    std::unordered_set<GuidPrefix_t> authenticated_writers_;
};

inline std::ostream& operator<<(std::ostream& output, const DiscoveryEndpointInfo& entity_info) {  //LCOV_EXCL_START
    output << "\n=================================================================\n";
    output << "topic: " << entity_info.topic() << "\n";
    output << "is_virtual: " << (entity_info.is_virtual() ? "True" : "False") << "\n";
    output << "is_rpc: " << (entity_info.is_rpc() ? "True" : "False") << "\n";
    output << "reliability: " << (int)entity_info.get_qos().m_reliability.kind << "\n";
    output << "durability: " << (int)entity_info.get_qos().m_durability.kind << "\n";

    output << "history: " << (int)entity_info.get_qos().m_history.kind << " depth("
           << entity_info.get_qos().m_history.depth << ")\n";

    output << "deadline: " << entity_info.get_qos().m_deadline.period << "\n";

    output << "liveliness: lease_duration(" << entity_info.get_qos().m_liveliness.lease_duration
           << ") announcement_period(" << entity_info.get_qos().m_liveliness.announcement_period << ")\n";

    output << "isMultiSend: " << (entity_info.get_qos().m_isMultiSend ? "True" : "False") << "\n";
    output << "e2eProtecionEnabled: " << (entity_info.get_qos().m_e2eProtecion.enabled ? "True" : "False") << "\n";
    output << "----------------------------------------------------------------\n";
    return output;
}  // LCOV_EXCL_STOP

} /* namespace ddb */
} /* namespace rtps */
} /* namespace ertps */
} /* namespace evbs */

#endif /* _EDDS_RTPS_ENDPOINT_INFO_H_ */
